package cn.js189.uqc.service.impl;

import cn.js189.common.constants.ErrorConstants;
import cn.js189.common.constants.InvoiceConstant;
import cn.js189.common.util.exception.BaseAppException;
import cn.js189.common.util.exception.ExceptionUtil;
import cn.js189.common.util.helper.UUIDHelper;
import cn.js189.uqc.common.QXInvoiceService;
import cn.js189.uqc.domain.*;
import cn.js189.uqc.domain.invoice.*;
import cn.js189.uqc.mapper.CheckInfoMapper;
import cn.js189.uqc.redis.RedisOperation;
import cn.js189.uqc.service.InvoiceService;
import cn.js189.uqc.util.EInvoiceUtil;
import cn.js189.uqc.util.InnerApiLogThread;
import cn.js189.uqc.util.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class InvoiceServiceImpl implements InvoiceService {

	private static final Logger LOGGER = LoggerFactory.getLogger(InvoiceServiceImpl.class);

	@Resource
	private CheckInfoMapper checkInfoMapper;

	@Resource
	private RedisOperation redisOperation;

	@Resource
	private QXInvoiceService qxInvoiceService;

	@Override
	public boolean commitInvoiceInfo(InvoiceOrder invoiceOrder, List<InvoiceOrderDetail> orderDetail, User user, String bizName) throws BaseAppException {

		String partyId = user.getPartyId();

		if (StringUtils.isEmpty(partyId)) {
			ExceptionUtil.throwBusiException(ErrorConstants.PARAM_EMPTY_USERTAIL);
		}

		try {
			// 插入订单总信息
			int orderNum = this.checkInfoMapper.insertInvoiceOrder(invoiceOrder);

			// 插入订单信息
			int orderDetailNum = this.checkInfoMapper.insertInvoiceOrderDetail(orderDetail);

			boolean f = (orderDetail.size() + 1 == (orderNum + orderDetailNum));
			if (!f) {
				return false;
			}

			LOGGER.info("插入订单信息成功 内部订单号:{} 订单发票{}条", invoiceOrder.getOrderId(), orderDetail.size());

			String lockValue = UUIDHelper.getUUID();
			String lockKey = InvoiceConstant.INIT_USER_INFO_PREFIX + partyId;
			String lockResult = RedisUtil.waitForTryLock(redisOperation, "发票订单信息入库", lockKey, lockValue);

			int row = 0;

			// 获取锁成功
			if (StringUtils.equals(lockResult, RedisUtil.LOCK_SUCCESS)) {
				// 用户信息
				User userInfo = this.checkInfoMapper.selectUserByPartyId(partyId);

				if (null != userInfo) {
					String taxNum = user.getTaxNum();
					String oldTaxNum = userInfo.getTaxNum();
					if (!StringUtils.isEmpty(oldTaxNum)) {
						if (!StringUtils.equals(taxNum, oldTaxNum)) {
							this.qxInvoiceService.insertOpertaionLog(bizName, InvoiceConstant.WX_USER_INFO_TABLENAME, InvoiceConstant.WX_USER_INFO_COLUMN_TAX_NUM, oldTaxNum, taxNum, partyId);
						}
					}
					user.setGmtUpdate(new Date());
					row = this.checkInfoMapper.updateUserInfos(user);
				} else {
					row = this.checkInfoMapper.insertUserInfos(user);
				}
				LOGGER.info("用户 {} 信息更新/插入成功", partyId);

				RedisUtil.unlock(redisOperation, "发票订单信息入库", lockKey, lockValue);

			}

			return row > 0;

		} catch (Exception ex) {
			LOGGER.error(ex.getMessage());
			return false;
		}
	}

	/**
	 * 账单id和产品实例id查询是否有发票信息
	 */
	@Override
	public InvoiceOrderDetail selectDetailByIdAndProductId(String id, String productId) {
		// 待确认 id+productId 是否能组成发票的唯一标识
		return this.checkInfoMapper.selectDetailByIdAndProductId(id, productId);
	}

	/**
	 * 更新发票信息
	 * 发票实例id作为唯一标识
	 */
	@Transactional
	@Override
	public int updateInvoiceOrderDetail(InvoiceOrderDetail invoiceOrderDetail) {
		invoiceOrderDetail.setGmtUpdate(new Date());
		return this.checkInfoMapper.updateInvoiceOrderDetail(invoiceOrderDetail);
	}

	/**
	 * 发票实例id查询发票详细信息
	 */
	@Override
	public InvoiceDetail selectInvoiceById(String invoiceId) {
		return this.checkInfoMapper.selectInvoiceById(invoiceId);
	}

	/**
	 * 发票实例id,用户id查询发票详细信息
	 */
	@Override
	public InvoiceDetail selectInvoiceById(String invoiceId,String partyId) {
		return this.checkInfoMapper.selectInvoiceByPartyId(invoiceId,partyId);
	}

	@Override
	public InvoiceDetail selectInvoiceType1000(InvoiceInfoDTO invoiceInfoDTO) {
		return this.checkInfoMapper.selectInvoiceType1000(invoiceInfoDTO);
	}
	
	@Override
	public InvoiceDetail selectInvoiceType1100(InvoiceInfoDTO invoiceInfoDTO) {
		return this.checkInfoMapper.selectInvoiceType1100(invoiceInfoDTO);
	}
	
	@Override
	public InvoiceDetail selectInvoiceType1200(InvoiceInfoDTO invoiceInfoDTO) {
		return this.checkInfoMapper.selectInvoiceType1200(invoiceInfoDTO);
	}	

	/**
	 * 根据订单id更新开票状态信息
	 */
	@Transactional
	@Override
	public int updateInvoiceDetailStatusByOrderId(String orderId, String status) {
		return this.checkInfoMapper.updateInvoiceDetailStatusByOrderId(orderId, status);
	}

	/**
	 * 更新发票信息
	 * 主键id作为唯一标识
	 */
	@Transactional
	@Override
	public int updateInvoiceOrderDetailByPK(InvoiceOrderDetail invoiceOrderDetail) {
		invoiceOrderDetail.setGmtUpdate(new Date());
		return this.checkInfoMapper.updateInvoiceOrderDetailByPK(invoiceOrderDetail);
	}

	/**
	 * 根据身份证查询用户信息
	 */
	@Override
	public User selectUserByIdCard(String idCard) {
		return this.checkInfoMapper.selectUserByPartyId(idCard);
	}

	/**
	 * 插入用户信息
	 */
	@Transactional
	@Override
	public int insertUserInfos(User user) {
		return this.checkInfoMapper.insertUserInfos(user);
	}

	/**
	 * 更新用户信息
	 */
	@Transactional
	@Override
	public int updateUserInfos(User user) {
		user.setGmtUpdate(new Date());
		return this.checkInfoMapper.updateUserInfos(user);
	}
	
    
	/**
	 * 1000
	 * 根据类型查询月结发票开票历史
	 */
	@Override
	public List<InvoiceHisDto> selectMonthlyHis(String phone, String type, String startTime, String endTime, String phoneType) {
		return this.checkInfoMapper.selectMonthlyHis(phone, type, startTime, endTime, phoneType);
	}

	/**
	 * 1100
	 * 根据类型查询实缴发票开票历史
	 */
	@Override
	public List<InvoiceHisDto> selectPaymentHis(String phone, String type, String startTime, String endTime, String phoneType) {
		return this.checkInfoMapper.selectPaymentHis(phone, type, startTime, endTime, phoneType);
	}

	/**
	 * 1200
	 * 根据类型查询营业厅订单发票开票历史
	 */
	@Override
	public List<InvoiceHisDto> selectOrderOneItemHis(String phone, String type, String startTime, String endTime, String phoneType) {
		return this.checkInfoMapper.selectOrderOneItemHis(phone, type, startTime, endTime, phoneType);
	}

	@Override
	public List<Map<String, String>> selectListByPartyId(String partyId){
		return this.checkInfoMapper.selectListByPartyId(partyId);
	}
	
	public List<QxError> initQxError() {
		try {
			LOGGER.info("初始化企信接口错误码信息...");
			
			boolean hasInit = EInvoiceUtil.checkErrmsgMap();
			if (!hasInit) {
				return null;
			}
			
			EInvoiceUtil.initErrmsgMap();
			LOGGER.info("初始化企信接口错误码信息Map...");
			
			List<QxError> errorList = this.checkInfoMapper.selectQxErrorInfo();
			
			LOGGER.info("企信接口错误码信息:{}", errorList);
			if (null != errorList && !errorList.isEmpty()) {
				
				EInvoiceUtil.cleanErrmsg();
				
				for (int i = 0; i < errorList.size(); i++) {
					QxError qxError = errorList.get(i);
					
					String errorCode = qxError.getErrorCode();
					String errorMsg = qxError.getErrorMsg();
					String message = qxError.getMessage();
					
					LOGGER.info("错误码:{} , 错误信息:{}", errorCode, message);
					EInvoiceUtil.setErrmsgMap(errorCode, StringUtils.isEmpty(message) ? errorMsg : message);
					
				}
			}
			
			LOGGER.info("初始化企信接口错误码信息success...");
			return errorList;
			
		} catch (Exception e) {
			LOGGER.info("初始化企信接口错误码信息 Exception...{}", e.getMessage());
			return null;
		}
	}
	
	public void insertData(String areaCode, String accNbr, String returnCode, String inputParam, String outParam, String serviceType) {
		ExecutorService executorService = Executors.newSingleThreadExecutor();
		InnerApiLog innerApiLog = new InnerApiLog(areaCode, "dzfp", accNbr, serviceType, returnCode, inputParam, outParam, "0");
		InnerApiLogThread innerApiLogThread = new InnerApiLogThread(innerApiLog);
		executorService.execute(innerApiLogThread);
		executorService.shutdown();
	}
	
}
